package sketch.instrumenter;

import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import randoop.util.Files;
import sketch.ounit.Observer;
import sketch.util.Checker;
import sketch.util.SketchUtil;

/**
 * A sample trace file format:
 * 
   START: packageName#typename#rewriteSize
   OBSERVE: map.size()@23
   VALUE: 1@V_T@ int
   OBSERVE: map.size()@25
   VALUE: 2@V_T@ int
   OBSERVE: map.size()@27
   VALUE: 3@V_T@ int
   OBSERVE: map.size()@29
   VALUE: 4@V_T@ int
   NO_EXCEPTION: @20
   NO_EXCEPTION: 
   EXCEPTION_TYPE: @20
   EXCEPTION_TYPE: java.lang.RuntimeException
   END: packageName#typename#rewriteSize

 * */
public class TracerFileReader {
	
	public final File f;
	
	public TracerFileReader(String filePath) {
		Checker.checkNull(filePath, "The file: " + filePath  + " does not exist!");
		File f = new File(filePath);
		Checker.checkTrue(f.exists(), "The file: " + filePath + " does not exist!");
		this.f = f;
	}
	
	public TracerFileReader(File f) {
		Checker.checkNull(f, "The given file could not be null.");
		this.f = f;
	}
	
	public Map<String, Map<Integer, String>> parse() {
		System.out.println("Parsing file: " + this.f);
		try {
			return this.readFileContent();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	private Map<String, Map<Integer, String>> readFileContent() throws IOException {
		Map<String, Map<Integer, String>> retMap = new LinkedHashMap<String, Map<Integer, String>>();
		List<String> lineList = Files.readWhole(this.f);
		//parse each line
		boolean hasStart = false;
		boolean hasEnd = false;
		List<String> linesForEachTest = null;
		String currentTest = null;
		for(int i = 0; i < lineList.size(); i++) {
			String line = lineList.get(i);
			if(line.trim().equals("")) {
				continue;
			}
			if(line.startsWith(Tracer.START)) {
				Checker.checkTrue(!hasStart, "State error, hasStart is true now, in : " + i + "th line: " + line);
				hasStart = true;
				hasEnd = false;
				linesForEachTest = new LinkedList<String>();
				currentTest = line.substring(Tracer.START.length() - 1).trim();
			} else if (line.startsWith(Tracer.END)) {
				Checker.checkTrue(hasStart, "State error, hasStart is false!");
				Checker.checkTrue(!hasEnd, "hasEnd is true");
				hasStart = false;
				hasEnd = true;
				String test = line.substring(Tracer.END.length() - 1).trim();
				Checker.checkTrue(currentTest.equals(test), "Tests are not equal, test: " + test
						+ "  and, currentTest: " + currentTest);
				//process the list
				Map<Integer, String> results = this.createResultsForEachTest((String[])linesForEachTest.toArray(new String[0]));
				retMap.put(currentTest, results);
			} else {
//				continue;
				//can not check, because a random test gen may use Observer method
				//so the Observer method 
				Checker.checkNull(linesForEachTest, "The string list is null!");
				linesForEachTest.add(line);
			}
		}
		
		return retMap;
	}
	
	private Map<Integer, String> createResultsForEachTest(String[] lines) {
		Map<Integer, String> results = new LinkedHashMap<Integer, String>();
		
		int length = lines.length;
		Checker.checkTrue(length % 2 == 0, "The length of given input: " + length + " is not valid, the array is: " + SketchUtil.arrayToString(lines));
		if(length == 0) {
			return results;
		}
		//SketchUtil.createArray(items)
		//parse the file
		for(int i = 0; i < length; ) {
			String observer = lines[i].trim();
			String result = lines[i+1].trim();
			
			if(observer.trim().startsWith(Tracer.VALUE)) {
				String tmp = observer;
				observer = result;
				result = tmp;
			}
			
			int lineNum = Integer.valueOf(observer.substring(observer.indexOf(Tracer.SEP) + 1));
			String value = result.substring(Tracer.VALUE.length() - 1).trim();
//			if(value.indexOf(Observer.VALUE_TYPE_SEP) != -1) {
//			    value = value.substring(0, value.indexOf(Observer.VALUE_TYPE_SEP));//remove the value_type_sep
//			}
			results.put(lineNum, value); //XXX pretty ugly here, the value need to parse again
			i = i + 2;
		}
		return results;
	}
	
	public static String parseValue(String value) {
		if(value.indexOf(Observer.VALUE_TYPE_SEP) != -1) {
		    value = value.substring(0, value.indexOf(Observer.VALUE_TYPE_SEP));//remove the value_type_sep
		}
		return value;
	}
	
	public static boolean isStringType(String value) {
		if(value.indexOf(Observer.VALUE_TYPE_SEP) != -1) {
		    value = value.substring(value.indexOf(Observer.VALUE_TYPE_SEP) + Observer.VALUE_TYPE_SEP.length());//remove the value_type_sep
		    //System.out.println(value);
		    return value.equals("java.lang.String");
		} else {
			return false;
		}
	}
}
